package com.sapitest.utils.redis;

import com.sapitest.utils.ConfigFile;
import com.sapitest.utils.bean.RedisConnInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * Redis工具类
 * @date 2019-04-20
 * @author Liuxu
 * @version 1.0.1
 * @since jdk1.8
 */
public class Redis {
    private static final Logger logger = LoggerFactory.getLogger(Redis.class);

    private static int MAX_TOTAL = Integer.parseInt(ConfigFile.getSystemParameter("redis_max_total"));
    private static int MAX_IDLE = Integer.parseInt(ConfigFile.getSystemParameter("redis_max_idle"));
    private static int MAX_WAIT = Integer.parseInt(ConfigFile.getSystemParameter("redis_max_wait_millis"));
    private static int CONNECT_TIMEOUT = Integer.parseInt(ConfigFile.getSystemParameter("redis_connect_timeout"));
    private static boolean TEST_ON_BORROW = Boolean.parseBoolean(ConfigFile.getSystemParameter("redis_test_on_borrow"));
    private static boolean TEST_ON_RETURN = Boolean.parseBoolean(ConfigFile.getSystemParameter("redis_test_on_return"));

    private static Jedis jedis = null;

    private Redis(RedisConnInfo redisConnInfo){
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(MAX_TOTAL);
        config.setMaxIdle(MAX_IDLE);
        config.setMaxWaitMillis(MAX_WAIT);
        config.setTestOnBorrow(TEST_ON_BORROW);
        config.setTestOnReturn(TEST_ON_RETURN);
        JedisPool jedisPool = new JedisPool(config, redisConnInfo.getHost(), redisConnInfo.getPort(), CONNECT_TIMEOUT, redisConnInfo.getPassword());
        try {
            jedis = jedisPool.getResource();
        } catch (Exception e) {
            logger.error(e + "");
        }
    }

    /**
     * Redis工具类实例化
     * @param host  redis ip
     * @param pwd   redis 密码
     * @param port  redis 端口
     * @return  Redis工具类对象
     */
    public static Redis newInstance(String host, String pwd, int port){
        RedisConnInfo redisConnInfo = new RedisConnInfo(host, pwd, port);
        return new Redis(redisConnInfo);
    }

    /**
     * 执行redis命令
     * @param command   执行的命令，例如get，set，hget等
     * @param parameters    执行命令的参数，0个，1个或者多个
     * @param <T>   泛型
     * @return  执行成功：字符串 ；执行失败：null
     */
    @SuppressWarnings("unchecked")
    public <T> T execCommand(String command, String... parameters) {
        List<String> list = new ArrayList<>(Arrays.asList(parameters));
        String[] arg = list.toArray(new String[0]);
        try {
            Commands cmds = new Commands(jedis);
            Class cls = cmds.getClass();
            Method method = cls.getMethod(command.toLowerCase(), String[].class);
            logger.info("调用Redis方法" + command.toLowerCase());
            return (T) Objects.requireNonNull(method).invoke(cmds, new Object[]{arg});
        } catch (NoSuchMethodException e) {
            logger.error(e + ": Error method." );
        } catch (SecurityException | IllegalAccessException e) {
            logger.error("" + e);
        } catch (InvocationTargetException e) {
            logger.error(e + ": jedis error, jedis=" + jedis);
        } catch (IllegalArgumentException e) {
            logger.error(e + ": Error argument, parameters=" + list);
        } finally {
            jedis.close();
        }
        return null;
    }
}
